/*
 * MIT License
 *
 * Copyright (c) 2019 Mr.css
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package cn.seaboot.commons.core;

import com.google.common.base.Joiner;
import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.function.Function;
import java.util.function.ToDoubleFunction;
import java.util.stream.Collectors;

/**
 * 集合工具
 *
 * @author Mr.css 2017-08-14 14:48:35
 */
public class ListUtils {
    private ListUtils() {
    }

//    public static void main(String[] args) {
//        List<Map<String, Object>> list = new ArrayList<>();
//        list.add(MapUtils.newMap("pid", "0", "field", "age", "value", 1));
//        list.add(MapUtils.newMap("pid", "a", "field", "name", "value", "black"));
//        list.add(MapUtils.newMap("pid", "a", "field", "age", "value", 3));
//
//        Object ret = list.stream().collect(Collectors.toMap(e->"pid", e-> e));
//        System.out.println(ret);
//    }


    /**
     * 取出集合中的第一个元素
     * <p>
     * 这个在 mybatis 环境下会非常有用
     *
     * @param list 集合
     * @param <T>  泛型
     * @return 第一个元素
     */
    public static <T> T getFirst(List<T> list) {
        return CommonUtils.isEmpty(list) ? null : list.get(0);
    }


    /**
     * 取出集合中的最后一个元素
     * <p>
     * 因为 add 通常会添加到集合末尾，特殊业务下，可能更倾向于取最新的一个，这个在 mybatis 环境下会非常有用
     *
     * @param list 集合
     * @param <T>  泛型
     * @return 第一个元素
     */
    public static <T> T getLast(List<T> list) {
        return CommonUtils.isEmpty(list) ? null : list.get(list.size() - 1);
    }

    /**
     * 按照逗号join数组
     *
     * @param array 数组
     * @param <T>   泛型
     * @return String
     */
    public static <T> String join(@NotNull Collection<T> array) {
        return Joiner.on(',').join(array);
    }

    /**
     * 将离散的 ListMap，转换为对象列表
     * <p>
     * 在数据库查询中，经常会出现 select id, field, count(0) as value group by id, field 的情况，
     * 需要将数据转换为对象实体。
     * <p>
     * List<Map<String, Object>> list = new ArrayList<>();
     * list.add(MapUtils.newMap("id", "a", "field", "age", "value", 1));
     * list.add(MapUtils.newMap("id", "a", "field", "name", "value", "black"));
     * list.add(MapUtils.newMap("id", "b", "field", "age", "value", 3));
     * [{name=black, id=a, age=1}, {id=b, age=3}]
     * </>
     *
     * @param list  数据列表
     * @param id    主键key值
     * @param field 字段key值
     * @param value 数值key值
     * @return 新的数组
     */
    public static List<Map<String, Object>> groupingByToMap(@NotNull List<Map<String, Object>> list, String id, String field, String value) {
        List<Map<String, Object>> ret = new ArrayList<>();
        for (Map<String, Object> map : list) {
            Object uuid = map.get(id);
            Map<String, Object> params = null;
            for (Map<String, Object> m : ret) {
                if (m.get(id).equals(uuid)) {
                    params = m;
                    break;
                }
            }
            if (params == null) {
                params = new HashMap<>();
                params.put(id, uuid);
                ret.add(params);
            }
            params.put(Converter.toString(map.get(field)), map.get(value));
        }
        return ret;
    }

    /**
     * 数组转List
     *
     * @param t   数组
     * @param <T> -
     * @return list
     */
    @SafeVarargs
	public static <T> List<T> newLinkedList(T... t) {
        List<T> l = new LinkedList<>();
        if (t.length > 0) {
            Collections.addAll(l, t);
        }
        return l;
    }

    /**
     * 数组转List
     *
     * @param t   数组
     * @param <T> -
     * @return list
     */
    @SafeVarargs
	public static <T> List<T> newArrayList(T... t) {
        List<T> l = new ArrayList<>();
        Collections.addAll(l, t);
        return l;
    }

    /**
     * 分组生成新的 Map
     *
     * @param array 数组
     * @param <T>   泛型
     * @return String
     * @deprecated 仅作为代码参考
     */
    @Deprecated
    public static <T, K, U> Map<K, U> toMap(List<T> array, Function<? super T, ? extends K> keyMapper,
                                            Function<? super T, ? extends U> valueMapper) {
        return array.stream().collect(Collectors.toMap(keyMapper, valueMapper));
    }

    /**
     * 使用java8的特性，对集合进行分组
     *
     * @param list       数组
     * @param classifier 返回用于分组的字段值
     * @param <T>        对象泛型
     * @param <K>        用于比较的字段泛型
     * @return Map
     * @deprecated 仅作为代码参考
     */
    @Deprecated
    public static <T, K> Map<K, List<T>> groupingBy(List<T> list, Function<T, K> classifier) {
        return list.stream().collect(Collectors.groupingBy(classifier));
    }

    /**
     * 使用java8的特性，对集合进行分组，计算每个分组的数据量
     *
     * @param list       数组
     * @param classifier 返回用于分组的字段值
     * @param <T>        对象泛型
     * @param <K>        用于比较的字段泛型
     * @return Map
     * @deprecated 仅作为代码参考
     */
    @Deprecated
    public static <T, K> Map<K, Long> groupCount(List<T> list, Function<T, K> classifier) {
        return list.stream()
                .collect(Collectors.groupingBy(classifier, Collectors.counting()));
    }

    /**
     * 使用java8的特性，对集合进行分组，计算每个分组的和
     *
     * @param list       数组
     * @param classifier 返回用于分组的字段值
     * @param function   返回用于求和的字段值
     * @param <T>        list集合泛型
     * @param <K>        用于比较的字段泛型
     * @return Map
     * @deprecated 仅作为代码参考
     */
    @Deprecated
    public static <T, K> Map<K, Double> groupSum(List<T> list, Function<T, K> classifier, ToDoubleFunction<T> function) {
        return list.stream()
                .collect(Collectors.groupingBy(classifier, Collectors.summingDouble(function)));
    }

    /**
     * 使用java8的特性，对集合进行分组，计算每个分组的均值
     *
     * @param list       数组
     * @param classifier 返回用于分组的字段值
     * @param <T>        list集合泛型
     * @param <K>        用于比较的字段泛型
     * @return Map
     * @deprecated 仅作为代码参考
     */
    @Deprecated
    public static <T, K> Map<K, Double> groupAvg(List<T> list, Function<T, K> classifier, ToDoubleFunction<T> function) {
        return list.stream()
                .collect(Collectors.groupingBy(classifier, Collectors.averagingDouble(function)));
    }
}
